<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="wb6Ww" id="wb6Ww"><span data-lake-id="ub55a356c" id="ub55a356c">典型回答</span></h1>
  <p data-lake-id="u86f6e064" id="u86f6e064"><br></p>
  <p data-lake-id="uf1320b06" id="uf1320b06"><span data-lake-id="u1a4da2e4" id="u1a4da2e4">逃逸分析是Java HotSpot Server编译器中JIT优化的一个重要步骤。它在Java SE 6u23及以后的版本中默认启用。</span></p>
  <p data-lake-id="u7206f6b9" id="u7206f6b9"><span data-lake-id="u2ee71b41" id="u2ee71b41">​</span><br></p>
  <p data-lake-id="udf58e4e8" id="udf58e4e8"><br></p>
  <p data-lake-id="uef5b153b" id="uef5b153b"><span data-lake-id="ua4dbf25e" id="ua4dbf25e">对象基于逃逸分析可以有三种状态：全局逃逸（GlobalEscape）、参数逃逸（ArgEscape）和无逃逸（NoEscape）。</span></p>
  <p data-lake-id="u99e8edd7" id="u99e8edd7"><span data-lake-id="uc7e5bee1" id="uc7e5bee1">​</span><br></p>
  <ol list="ud94aefda">
   <li fid="uc06f5788" data-lake-id="u976a9047" id="u976a9047"><strong><span data-lake-id="uac1e506c" id="uac1e506c">全局逃逸（GlobalEscape）</span></strong><span data-lake-id="ud7c22b2e" id="ud7c22b2e">：对象超出了方法或线程的范围，比如被存储在静态字段或作为方法的返回值。</span></li>
  </ol>
  <p data-lake-id="ube722f7a" id="ube722f7a"><span data-lake-id="u74d257ab" id="u74d257ab">​</span><br></p>
  <pre lang="java"><code>
public class GlobalEscapeExample {
    private static Object staticObject;

    public void globalEscape() {
        staticObject = new Object(); // 这个对象赋值给静态字段，因此它是全局逃逸的
    }
}

public static StringBuffer craeteStringBuffer(String s1, String s2) {
    StringBuffer sb = new StringBuffer();
    sb.append(s1);
    sb.append(s2);
    return sb;
}
</code></pre>
  <p data-lake-id="u2db620dc" id="u2db620dc"><br></p>
  <p data-lake-id="u1996e90c" id="u1996e90c"><span data-lake-id="u39a75b1e" id="u39a75b1e">如我们新建的staticObject就是全局逃逸的。以及下面的方法中的sb对象，也是全局逃逸的。</span></p>
  <p data-lake-id="u4cd0aca2" id="u4cd0aca2"><span data-lake-id="u95ca758c" id="u95ca758c">​</span><br></p>
  <ol list="ud94aefda" start="2">
   <li fid="uc06f5788" data-lake-id="u506d8a1b" id="u506d8a1b"><strong><span data-lake-id="u3706af41" id="u3706af41">参数逃逸（ArgEscape）</span></strong><span data-lake-id="u79f9a128" id="u79f9a128">：对象被作为参数传递或被参数引用，但在方法调用期间不会全局逃逸。</span></li>
  </ol>
  <p data-lake-id="u38cec182" id="u38cec182"><span data-lake-id="uc62e8c39" id="uc62e8c39">​</span><br></p>
  <pre lang="java"><code>
public class ArgEscapeExample {
    public void methodA() {
        Object localObject = new Object();
        methodB(localObject); // localObject作为参数传递，但不会从methodB中逃逸
    }

    public void methodB(Object param) {
        // 在这里使用param
    }
}
</code></pre>
  <p data-lake-id="u32eb8072" id="u32eb8072"><br></p>
  <p data-lake-id="ua34b2eac" id="ua34b2eac"><span data-lake-id="uc3d724b2" id="uc3d724b2">如传递到methodB中的param对象，就是发生了参数逃逸的。因为他从methodA中逃逸到了methodB中。</span></p>
  <p data-lake-id="u196fa32f" id="u196fa32f"><span data-lake-id="u76dd8cdc" id="u76dd8cdc">​</span><br></p>
  <ol list="ud94aefda" start="3">
   <li fid="uc06f5788" data-lake-id="u1a3b720f" id="u1a3b720f"><strong><span data-lake-id="u659dbf3c" id="u659dbf3c">无逃逸（NoEscape）</span></strong><span data-lake-id="u536a6c8c" id="u536a6c8c">：对象可以被标量替换，意味着它的内存分配可以从生成的代码中移除。</span></li>
  </ol>
  <p data-lake-id="u505413e1" id="u505413e1"><span data-lake-id="u9fe02959" id="u9fe02959">​</span><br></p>
  <pre lang="java"><code>
public static String createStringBuffer(String s1, String s2) {
    StringBuffer sb = new StringBuffer();
    sb.append(s1);
    sb.append(s2);
    return sb.toString();
}
</code></pre>
  <p data-lake-id="u0f68e759" id="u0f68e759"><br></p>
  <p data-lake-id="u081a8609" id="u081a8609"><span data-lake-id="u066f1f74" id="u066f1f74">如上面的sb，就没有发生逃逸，因为这个对象本身没有作为参数传递，也没有被当做方法返回值，并没有赋值给静态变量。</span></p>
  <p data-lake-id="ua1cf1ca2" id="ua1cf1ca2"><span data-lake-id="u94860c4d" id="u94860c4d">​</span><br></p>
  <p data-lake-id="ua9401fe5" id="ua9401fe5"><span data-lake-id="u6a191484" id="u6a191484">在Java中，不同的逃逸状态影响JIT（即时编译器）的优化策略：</span></p>
  <ol list="u12cc8dc5">
   <li fid="ufed142f7" data-lake-id="ub3111516" id="ub3111516"><strong><span data-lake-id="ubdf0ef28" id="ubdf0ef28">全局逃逸（GlobalEscape）</span></strong><span data-lake-id="u1806fad8" id="u1806fad8">：由于对象可能被多个线程访问，全局逃逸的对象一般不适合进行栈上分配或其他内存优化。但JIT可能会进行其他类型的优化，如方法内联或循环优化。（方法内联参考：</span><a href="https://www.yuque.com/hollis666/vhr2ge/nkr4ge#ovn99" data-lake-id="u5e55d4eb" id="u5e55d4eb"><span data-lake-id="u0f43d9aa" id="u0f43d9aa">https://www.yuque.com/hollis666/vhr2ge/nkr4ge#ovn99</span></a><span data-lake-id="uc2258688" id="uc2258688"> ）</span></li>
   <li fid="ufed142f7" data-lake-id="u889f449e" id="u889f449e"><strong><span data-lake-id="u0b6118b1" id="u0b6118b1">参数逃逸（ArgEscape）</span></strong><span data-lake-id="ud81524cc" id="ud81524cc">：这种情况下，对象虽然作为参数传递，但不会被方法外部的代码使用。JIT可以对这些对象进行一些优化，例如锁消除</span></li>
   <li fid="ufed142f7" data-lake-id="uebd82e78" id="uebd82e78"><strong><span data-lake-id="u1372aa1f" id="u1372aa1f">无逃逸（NoEscape）</span></strong><span data-lake-id="u1bc3d5f6" id="u1bc3d5f6">：这是最适合优化的情况。JIT可以采取多种优化措施，如在栈上分配内存，消除锁，甚至完全消除对象分配（标量替换）。这些优化可以显著提高性能，减少垃圾收集的压力。</span></li>
  </ol>
  <p data-lake-id="u994be8be" id="u994be8be"><br></p>
  <table data-lake-id="WpADH" id="WpADH" margin="true" width-mode="contain" class="lake-table" style="width: 652px">
   <colgroup>
    <col width="122">
    <col width="172">
    <col width="200">
    <col width="158">
   </colgroup>
   <tbody>
    <tr data-lake-id="u2a6901d7" id="u2a6901d7">
     <td data-lake-id="u423670fb" id="u423670fb">
      <p data-lake-id="u820cc77b" id="u820cc77b"><strong><span data-lake-id="u86c04ce7" id="u86c04ce7">优化手段</span></strong></p></td>
     <td data-lake-id="ucb4ac22c" id="ucb4ac22c">
      <p data-lake-id="uf67a0415" id="uf67a0415"><strong><span data-lake-id="u45f8690c" id="u45f8690c">全局逃逸</span></strong></p></td>
     <td data-lake-id="ufb1c8dff" id="ufb1c8dff">
      <p data-lake-id="u61bd514b" id="u61bd514b"><strong><span data-lake-id="ud79010c6" id="ud79010c6">参数逃逸</span></strong></p></td>
     <td data-lake-id="u79b2d5d7" id="u79b2d5d7">
      <p data-lake-id="ub257b12c" id="ub257b12c"><strong><span data-lake-id="u6276f7cf" id="u6276f7cf">无逃逸</span></strong></p></td>
    </tr>
    <tr data-lake-id="uaea15d60" id="uaea15d60">
     <td data-lake-id="ufd457588" id="ufd457588">
      <p data-lake-id="u2584ee2d" id="u2584ee2d"><strong><span data-lake-id="u72962fb3" id="u72962fb3">方法内联</span></strong></p></td>
     <td data-lake-id="u6b0c152e" id="u6b0c152e">
      <p data-lake-id="u95cf811d" id="u95cf811d"><span data-lake-id="u9546be58" id="u9546be58">Y</span></p></td>
     <td data-lake-id="ufce776ae" id="ufce776ae">
      <p data-lake-id="ua42dac0f" id="ua42dac0f"><span data-lake-id="uc3e7efb6" id="uc3e7efb6">Y</span></p></td>
     <td data-lake-id="u59794f0a" id="u59794f0a">
      <p data-lake-id="u05269022" id="u05269022"><span data-lake-id="ubdfd3a61" id="ubdfd3a61">Y</span></p></td>
    </tr>
    <tr data-lake-id="ueea42717" id="ueea42717">
     <td data-lake-id="ub44c32e0" id="ub44c32e0">
      <p data-lake-id="uf02c1f3b" id="uf02c1f3b"><strong><span data-lake-id="u24ca0409" id="u24ca0409">循环优化</span></strong></p></td>
     <td data-lake-id="u1bf426a9" id="u1bf426a9">
      <p data-lake-id="u41bd887f" id="u41bd887f"><span data-lake-id="uaf7060c4" id="uaf7060c4">Y</span></p></td>
     <td data-lake-id="u600ea5b7" id="u600ea5b7">
      <p data-lake-id="udcde2306" id="udcde2306"><span data-lake-id="u5f10a3f8" id="u5f10a3f8">Y</span></p></td>
     <td data-lake-id="uf601cdd8" id="uf601cdd8">
      <p data-lake-id="ub4032a79" id="ub4032a79"><span data-lake-id="ucd9e31e4" id="ucd9e31e4">Y</span></p></td>
    </tr>
    <tr data-lake-id="uf5d98adb" id="uf5d98adb">
     <td data-lake-id="uce2f8652" id="uce2f8652">
      <p data-lake-id="ud3f32c5c" id="ud3f32c5c"><strong><span data-lake-id="ue421921a" id="ue421921a">锁消除</span></strong></p></td>
     <td data-lake-id="u067349f1" id="u067349f1">
      <p data-lake-id="u4436622f" id="u4436622f"><span data-lake-id="u15fa07dd" id="u15fa07dd">N</span></p></td>
     <td data-lake-id="u2b87f67f" id="u2b87f67f">
      <p data-lake-id="ua3f3f1c6" id="ua3f3f1c6"><span data-lake-id="uc5883b83" id="uc5883b83">Y</span></p></td>
     <td data-lake-id="uc702a8d2" id="uc702a8d2">
      <p data-lake-id="u5bd289ff" id="u5bd289ff"><span data-lake-id="u2cefa502" id="u2cefa502">Y</span></p></td>
    </tr>
    <tr data-lake-id="u60c49708" id="u60c49708">
     <td data-lake-id="u1b627587" id="u1b627587">
      <p data-lake-id="u153a92b3" id="u153a92b3"><strong><span data-lake-id="u31b462d7" id="u31b462d7">栈上分配</span></strong></p></td>
     <td data-lake-id="u6ad84d71" id="u6ad84d71">
      <p data-lake-id="u066998b7" id="u066998b7"><span data-lake-id="u7c9d2299" id="u7c9d2299">N</span></p></td>
     <td data-lake-id="uc45dfee6" id="uc45dfee6">
      <p data-lake-id="u2068e1e7" id="u2068e1e7"><span data-lake-id="u6dc2ab8f" id="u6dc2ab8f">N</span></p></td>
     <td data-lake-id="u449e6124" id="u449e6124">
      <p data-lake-id="ufe4c499c" id="ufe4c499c"><span data-lake-id="ud12a48fb" id="ud12a48fb">Y</span></p></td>
    </tr>
   </tbody>
  </table>
  <p data-lake-id="uf4b49611" id="uf4b49611"><br></p>
  <p data-lake-id="u2fb8c894" id="u2fb8c894"><span data-lake-id="u007b80c4" id="u007b80c4">总的来说，JIT编译器根据对象的逃逸状态采用不同的优化策略，以提高Java程序的性能和效率。</span></p>
  <p data-lake-id="u6f3e0e38" id="u6f3e0e38"><span data-lake-id="u38262bee" id="u38262bee">​</span><br></p>
  <h1 data-lake-id="RrzBh" id="RrzBh"><span data-lake-id="udec0d09c" id="udec0d09c">扩展知识</span></h1>
  <p data-lake-id="ud110280d" id="ud110280d"><br></p>
  <h2 data-lake-id="Ke1Xi" id="Ke1Xi"><span data-lake-id="u278e634b" id="u278e634b">开启逃逸分析</span></h2>
  <p data-lake-id="u9122b8db" id="u9122b8db"><span data-lake-id="u923b0afc" id="u923b0afc">​</span><br></p>
  <p data-lake-id="u26f2cea3" id="u26f2cea3"><span data-lake-id="ue1d1f790" id="ue1d1f790">在Java代码运行时，通过JVM参数可指定是否开启逃逸分析，</span></p>
  <p data-lake-id="u8a7a7409" id="u8a7a7409"><span data-lake-id="ua2817b5c" id="ua2817b5c">​</span><br></p>
  <p data-lake-id="ue772d6ca" id="ue772d6ca"><code data-lake-id="u54810584" id="u54810584"><span data-lake-id="u91f4f7ac" id="u91f4f7ac">-XX:+DoEscapeAnalysis</span></code><span data-lake-id="ucb632e46" id="ucb632e46">： 表示开启逃逸分析</span></p>
  <p data-lake-id="ue48047cf" id="ue48047cf"><code data-lake-id="u96025727" id="u96025727"><span data-lake-id="u4dbe0b41" id="u4dbe0b41">-XX:-DoEscapeAnalysis</span></code><span data-lake-id="u08fd2a05" id="u08fd2a05"> ： 表示关闭逃逸分析 从jdk 1.7开始已经默认开始逃逸分析，如需关闭，需要指定-XX:-DoEscapeAnalysis</span></p>
  <p data-lake-id="ubf498eb6" id="ubf498eb6"><span data-lake-id="u801e573b" id="u801e573b">​</span><br></p>
  <h2 data-lake-id="itBms" id="itBms"><span data-lake-id="ubdf7b3e0" id="ubdf7b3e0">逃逸分析并不成熟</span></h2>
  <p data-lake-id="u85445702" id="u85445702"><span data-lake-id="uae6d1385" id="uae6d1385">关于逃逸分析的论文在1999年就已经发表了，但直到JDK 1.6才有实现，而且这项技术到如今也并不是十分成熟的。</span></p>
  <p data-lake-id="ub6502efc" id="ub6502efc"><span data-lake-id="u8854a583" id="u8854a583">​</span><br></p>
  <p data-lake-id="u4163433b" id="u4163433b"><span data-lake-id="u10805214" id="u10805214">其根本原因就是无法保证逃逸分析的性能消耗一定能高于他的消耗。虽然经过逃逸分析可以做标量替换、栈上分配、和锁消除。但是逃逸分析自身也是需要进行一系列复杂的分析的，这其实也是一个相对耗时的过程。</span></p>
  <p data-lake-id="u10708215" id="u10708215"><span data-lake-id="uf6fd3191" id="uf6fd3191">一个极端的例子，就是经过逃逸分析之后，发现没有一个对象是不逃逸的。那这个逃逸分析的过程就白白浪费掉了。</span></p>
  <p data-lake-id="u3c49686c" id="u3c49686c"><span data-lake-id="ue82c47de" id="ue82c47de">​</span><br></p>
  <p data-lake-id="u3f032f4e" id="u3f032f4e"><span data-lake-id="u1510ef41" id="u1510ef41">虽然这项技术并不十分成熟，但是他也是即时编译器优化技术中一个十分重要的手段。</span></p>
  <p data-lake-id="ubcacca14" id="ubcacca14"><br></p>
 </body>
</html>